﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Hosting;
using System.Web.Mvc;
using EPiServer;
using EPiServer.Core;
using EPiServer.Shell;
using EPiServer.Web.Hosting;
using System.Linq;
using OpenWaves.EPiServer.ImageProperty;
using OpenWaves.ImageTransformations;
using OpenWaves.ImageTransformations.Web;

namespace OpenWaves.EPiServer.ImageBrowser
{
    public class ImageBrowserController : Controller
    {
        private readonly IWebImageTransformationService _transformationService;
        private readonly string[] _validExtensions;

        public ImageBrowserController()
        {
            this._validExtensions = ImageSettingsAttribute.ImageExtensions.Select(ext => ext.ToLowerInvariant()).ToArray();
            this._transformationService = ServiceLocator.Resolve<IWebImageTransformationService>();
        }

        public JsonResult GetImages(string contextId, string path, string searchTerm, bool searchRecursive)
        {
            if (string.IsNullOrEmpty(path))
            {
                return this.Json(false, JsonRequestBehavior.AllowGet);
            }

            return this.Json(this.GetDirectoryChildren(contextId, path, searchTerm, searchRecursive), JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public JsonResult CreateNewDirectory(string directoryName, string path)
        {
            var contextId = string.Empty;

            if (string.IsNullOrEmpty(path))
            {
                return this.GetFailedResult();
            }

            var virtualDirectory = HostingEnvironment.VirtualPathProvider.GetDirectory(path) as UnifiedDirectory;
            if (virtualDirectory == null)
            {
                return this.GetFailedResult();
            }

            var subDirectory = virtualDirectory.CreateSubdirectory(directoryName);

            var items = this.GetImages(contextId, path, string.Empty, false);

            return new JsonResult { Data = new { result = true, items = items.Data } };
        }

        [HttpPost]
        public JsonResult SaveDirectoryName(string path, string name, string newName)
        {
            var contextId = string.Empty;

            if (string.IsNullOrEmpty(path))
            {
                return new JsonResult { Data = new { result = false } };
            }

            if (string.IsNullOrEmpty(newName))
            {
                return new JsonResult { Data = new { result = false } };
            }

            var directory = HostingEnvironment.VirtualPathProvider.GetDirectory(path);
            if (directory == null)
            {
                return new JsonResult { Data = new { result = false } };
            }

            var originalDirectory =
                directory.Directories.OfType<UnifiedDirectory>()
                         .FirstOrDefault(
                             d => string.Compare(d.Name, name, StringComparison.InvariantCultureIgnoreCase) == 0);

            if (originalDirectory != null)
            {
                var newPath = Path.Combine(path, newName);
                originalDirectory.MoveTo(newPath);
                return new JsonResult { Data = new { path = newPath, result = true } };
            }

            return new JsonResult { Data = new { result = false } };
        }

        [HttpPost]
        public JsonResult DeleteDirectory(string path, string name)
        {
            if (string.IsNullOrEmpty(path))
            {
                return new JsonResult { Data = new { result = false } };
            }

            if (string.IsNullOrEmpty(name))
            {
                return new JsonResult { Data = new { result = false } };
            }

            var directory = HostingEnvironment.VirtualPathProvider.GetDirectory(path);
            if (directory == null)
            {
                return new JsonResult { Data = new { result = false } };
            }

            var originalDirectory =
                directory.Directories.OfType<UnifiedDirectory>()
                         .FirstOrDefault(
                             d => string.Compare(d.Name, name, StringComparison.InvariantCultureIgnoreCase) == 0);

            if (originalDirectory != null)
            {
                originalDirectory.Delete();
                return new JsonResult { Data = new { result = true } };
            }

            return new JsonResult { Data = new { result = false } };
        }

        #region Page files

        public JsonResult IsPageFilesVppAvailable(string contextId)
        {
            var pageId = PageReference.Parse(contextId);
            var pageFilesDirectory = DataFactory.Instance.GetPage(pageId).GetPageDirectory(false);
            if (pageFilesDirectory == null)
            {
                return this.Json(null, JsonRequestBehavior.AllowGet);
            }
            return this.Json(pageFilesDirectory.VirtualPath, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public JsonResult EnsurePageFilesDirectory(string contextId)
        {
            var pageId = PageReference.Parse(contextId);
            var pageFilesPath = DataFactory.Instance.GetPage(pageId).GetPageDirectory(true).VirtualPath;
            return new JsonResult { Data = new { path = pageFilesPath, result = true } };
        }

        #endregion

        public static string GetControllerPath()
        {
            return Paths.ToResource(typeof(ImageBrowserController), "imageBrowser");
        }

        #region files

        public JsonResult GetFileDetails(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                return this.GetFailedResult();
            }
            fileName = fileName.Trim();

            fileName = System.Web.HttpUtility.UrlDecode(fileName);

            if (!HostingEnvironment.VirtualPathProvider.FileExists(fileName))
            {
                return this.GetFailedResult();
            }

            var file = HostingEnvironment.VirtualPathProvider.GetFile(fileName);

            var extension = Path.GetExtension(file.Name);
            if (string.IsNullOrWhiteSpace(extension) || extension.Length < 1)
            {
                return this.GetFailedResult();
            }
            extension = extension.Substring(1).ToLowerInvariant();

            if (!this._validExtensions.Contains(extension))
            {
                return this.GetFailedResult();
            }

            var vppName = string.Empty;
            var path = string.Empty;
            var unifiedFile = file as UnifiedFile;
            if (unifiedFile != null)
            {
                vppName = unifiedFile.Provider.ProviderName;
                path = unifiedFile.Parent.VirtualPath;
            }
            else
            {
                path = file.VirtualPath.Substring(0, file.VirtualPath.LastIndexOf('/') - 1);
            }

            return new JsonResult
            {
                Data =
                    new
                    {
                        result = true,
                        name = file.Name,
                        path,
                        vppName
                    },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };

        }

        private VirtualFile GetFile(string filename)
        {
            filename = HttpUtility.UrlDecode(filename);
            if (string.IsNullOrEmpty(filename))
            {
                return null;
            }

            var file = HostingEnvironment.VirtualPathProvider.GetFile(filename);
            return file;
        }

        [HttpPost]
        public JsonResult RenameFile(string filename, string newName)
        {
            var file = this.GetFile(filename) as UnifiedFile;
            if (file == null)
            {
                return new JsonResult { Data = new { result = false } };
            }

            var extension = Path.GetExtension(filename);
            newName = newName + extension;

            var newPath = Path.Combine(Path.GetDirectoryName(filename), newName);
            file.MoveTo(newPath);
            return new JsonResult { Data = new { result = true } };
        }

        [HttpPost]
        public JsonResult DeleteFile(string filename)
        {
            var file = this.GetFile(filename) as UnifiedFile;
            if (file == null)
            {
                return new JsonResult { Data = new { result = false } };
            }

            file.Delete();
            return new JsonResult { Data = new { result = true } };
        }

        #endregion

        private ImageGalleryDirectoryContent GetDirectoryChildren(string contextId, string virtualPath, string searchTerm, bool searchRecursive)
        {
            var virtualDirectory = HostingEnvironment.VirtualPathProvider.GetDirectory(virtualPath) as UnifiedDirectory;
            if (virtualDirectory == null)
            {
                return new ImageGalleryDirectoryContent();
            }

            var imageTransformation = new ScaleDownToFitTransformation(120, 75);
            var galleryImageFiles = this.GetDirectoryImages(virtualDirectory, imageTransformation, searchTerm).ToList();

            var galleryDirectories = new List<ImageBrowserDirectory>();
            var unifiedDirectories = virtualDirectory.GetDirectories();
            if (string.IsNullOrWhiteSpace(searchTerm))
            {

                foreach (var childDirectory in unifiedDirectories)
                {
                    var directoryThumbnails = this.GetDirectoryImages(childDirectory, imageTransformation, searchTerm).ToList();

                    galleryDirectories.Add(new ImageBrowserDirectory
                    {
                        Name = childDirectory.Name,
                        Path = childDirectory.VirtualPath,
                        Thumbnails = directoryThumbnails.Take(10).Select(t => t.ThumbnailPath),
                        CountImages = directoryThumbnails.Count
                    });
                }
            }
            else if (searchRecursive)
            {
                foreach (var childDirectory in unifiedDirectories)
                {
                    var childDirectoryContent = this.GetDirectoryChildren(contextId, childDirectory.VirtualPath, searchTerm, true);
                    galleryImageFiles.AddRange(childDirectoryContent.ImageFiles);
                }
            }

            return new ImageGalleryDirectoryContent
            {
                DirectoryName = virtualDirectory.Name,
                DirectoryPath = virtualDirectory.VirtualPath,
                ParentDirectoryName = virtualDirectory.Parent == null ? string.Empty : virtualDirectory.Parent.Name,
                ParentDirectoryPath = virtualDirectory.Parent == null ? string.Empty : virtualDirectory.Parent.VirtualPath,
                Directories = galleryDirectories,
                ImageFiles = galleryImageFiles
            };
        }

        private IEnumerable<ImageBrowserFile> GetDirectoryImages(UnifiedDirectory virtualDirectory, ImageTransformation imageTransformation, string searchTerm)
        {
            if (searchTerm != null)
            {
                searchTerm = searchTerm.ToLowerInvariant();
            }

            var galleryImageFiles = new List<ImageBrowserFile>();
            var unifiedFiles = virtualDirectory.GetFiles();
            foreach (var unifiedFile in unifiedFiles)
            {
                var extension = unifiedFile.Extension;
                if (string.IsNullOrEmpty(extension))
                {
                    continue;
                }
                if (!this._validExtensions.Contains(extension.Substring(1).ToLowerInvariant()))
                {
                    continue;
                }

                if (!string.IsNullOrWhiteSpace(searchTerm) &&
                    unifiedFile.Name != null &&
                    !unifiedFile.Name.ToLowerInvariant().StartsWith(searchTerm))
                {
                    continue;
                }

                if (!string.IsNullOrWhiteSpace(extension))
                {
                    extension = extension.Substring(1);
                }

                galleryImageFiles.Add(new ImageBrowserFile
                {
                    Name = unifiedFile.Name,
                    Path = unifiedFile.VirtualPath,
                    DisplayName = Path.GetFileNameWithoutExtension(unifiedFile.Name),
                    Extension = extension,
                    Size = GetSize(unifiedFile.Length),
                    ThumbnailPath = this._transformationService.GetTransformedImageUrl(OpenWaves.Url.Parse(unifiedFile.VirtualPath), imageTransformation).ToString(),
                });
            }
            return galleryImageFiles;
        }

        private static string GetSize(long length)
        {
            if (length > 1000000)
            {
                return length / 1000000 + " MB";
            }

            if (length > 1000)
            {
                return length / 1000 + " KB";
            }

            return length + " B";
        }

        private JsonResult GetFailedResult(JsonRequestBehavior jsonRequestBehavior = JsonRequestBehavior.AllowGet)
        {
            return new JsonResult { Data = new { result = false }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
        }

        #region DTO classes

        public class ImageGalleryDirectoryContent
        {
            public ImageGalleryDirectoryContent()
            {
                this.Directories = Enumerable.Empty<ImageBrowserDirectory>();
                this.ImageFiles = Enumerable.Empty<ImageBrowserFile>();
            }

            public string DirectoryName { get; set; }
            public string DirectoryPath { get; set; }
            public string ParentDirectoryName { get; set; }
            public string ParentDirectoryPath { get; set; }
            public IEnumerable<ImageBrowserDirectory> Directories { get; set; }
            public IEnumerable<ImageBrowserFile> ImageFiles { get; set; }
        }

        public class ImageBrowserDirectory
        {
            public ImageBrowserDirectory()
            {
                this.Thumbnails = Enumerable.Empty<string>();
            }

            public string Name { get; set; }
            public string Path { get; set; }
            public IEnumerable<string> Thumbnails { get; set; }
            public int CountImages { get; set; }
        }

        public class ImageBrowserFile
        {
            public string Name { get; set; }
            public string ThumbnailPath { get; set; }
            public string Path { get; set; }

            public string Size { get; set; }

            public string DisplayName { get; set; }
            public string Extension { get; set; }
        }

        #endregion
    }
}